(function (root, factory, undef) {
    if (typeof exports === 'object') {
        // CommonJS
        module.exports = exports = factory(require('./core'), require('./cipher-core'));
    } else {
        if (typeof define === 'function' && define.amd) {
            // AMD
            define(['./core', './cipher-core'], factory);
        } else {
            // Global (browser)
            factory(root.CryptoJS);
        }
    }
})(this, function (CryptoJS) {
    /**
     * Output Feedback block mode.
     */
    CryptoJS.mode.OFB = (function () {
        var OFB = CryptoJS.lib.BlockCipherMode.extend();
        var Encryptor = (OFB.Encryptor = OFB.extend({
            processBlock: function (words, offset) {
                // Shortcuts
                var cipher = this._cipher;
                var blockSize = cipher.blockSize;
                var iv = this._iv;
                var keystream = this._keystream; // Generate keystream

                if (iv) {
                    keystream = this._keystream = iv.slice(0); // Remove IV for subsequent blocks

                    this._iv = undefined;
                }

                cipher.encryptBlock(keystream, 0); // Encrypt

                for (var i = 0; i < blockSize; i++) {
                    words[offset + i] ^= keystream[i];
                }
            }
        }));
        OFB.Decryptor = Encryptor;
        return OFB;
    })();

    return CryptoJS.mode.OFB;
});
